/**
 * alarm.c
 */

#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <syslog.h>
#include <pthread.h>
#include <time.h>
#include <stdbool.h>

#include <Ipc.h>
// #include <../net/VideoRecord.h>
#include "Thread.h"

#include "alarmInspectsensor.h"
#include "jze/alarmMsg.h"
#include "alarmControl.h"
#include "alarmInterlock.h"

int msgid  = -1;
static int shmid_config = -1;
static int shmid_status = -1;

static struct devconfig *global_config = NULL;
static struct devstatus *global_status = NULL;

#define JCH_TEST
int g_runningAlarm = -1;
#define TOTAL_ALARM_TYPE    10
static pthread_t tid = 0;
AlarmEnv env;

static int initIPC(void) {
    if (msgid < 0) {
        if ((msgid = kmsg_open(IPC_PATH, IPC_MSG_PROJID)) < 0) {
            printf("[alarm]:msg init failed!\n");
            return -1;
        }
    }
    if ((global_config == NULL) || (global_status == NULL) ||
        (shmid_config == -1) || (shmid_status == -1)) {
        if (status_config_shm_init(&global_status, &global_config,
                                   &shmid_status, &shmid_config) < 0) {
            printf("[alarm]:status and config share men init failed!\n");
            return -1;
        }
    }

    return 0;
}

static inline void alarmFeedDog(void) {
	kshm_lock(shmid_status);
	global_status->appstats.alarm.dog = 0;
	kshm_unlock(shmid_status);
}

static inline bool isOnline(void) {
    kshm_lock(shmid_status);
    bool online = global_status->net_online;	// TODO: when change, remove all configure
    kshm_unlock(shmid_status);
    return online;
}

// TODO:
#define ALARM_CONF_FN ""
static void loadDefaultConf(AlarmEnv *pEnv, char *pFile) {
    int count,index = 0;
    char cmd;
    AlarmEnv env = {false, false, false, 0, -1, NULL,NULL,{{0},{0},{0},{0}}};
    *pEnv = env;	// because block {} can only be used as initialize
    count = global_config->alarmConf.aaSensorTotal;
    dbg("sensor count = %d",count);
    while( index < 4) {
        if(global_config->alarmConf.aaSensor[index][3] >= 1 /* sensor addr [1 - 4] */
            && global_config->alarmConf.aaSensor[index][3] <= 4 ) {
            Sensor *pSensor = NULL;
            pSensor = allocSensor(&global_config->alarmConf.aaSensor[index][0], &cmd);
            processSensorCmd(&pEnv->pSensorList, pSensor, cmd);
    #ifdef JCH_TEST
            {
                char aBuff[1024];
                int len;
                memset(aBuff, 0, sizeof(aBuff));
                len = sensorToBuff(aBuff, sizeof(aBuff), pSensor);
                printBuff("SENSOR", aBuff, len);
                printf("compare cmd and aBuff = %d,index = %d\n",
                    memcmp(&global_config->alarmConf.aaSensor[index][0], aBuff, len),index);
            }
    #endif
        }
        index++;
    }
}

static void saveAlarmConf(AlarmEnv *pEnv, struct devconfig *pConf) {
    kshm_lock(shmid_config);
    memset(&pConf->alarmConf, 0, sizeof(AlarmConf));

    // sensor conf
    pConf->alarmConf.aaSensorTotal = 0;
    Sensor *pSensor = pEnv->pSensorList;
    while (pSensor != NULL) {
        sensorToBuff(&pConf->alarmConf.aaSensor[pSensor->conf.addr - 1][0], SENSOR_BUFF_SIZE, pSensor);
        pConf->alarmConf.aaSensorTotal++;
        pSensor = pSensor->pNext;
    }
    // alarm msg
    pConf->alarmConf.alarmMsgMask = pEnv->alarmMsgMask;
    // alarm record
    Capturer *pCapturer = pEnv->pCapList;
    while (pCapturer != NULL) {
        capturerToBuff(&pConf->alarmConf.aaCapturer[(unsigned char)(pCapturer->id)][0], CAPTURER_BUFF_SIZE, pCapturer);
        pCapturer = pCapturer->pNext;
    }
    kshm_unlock(shmid_config);
    kmsg_add(msgid, MSGID_ALMHANDLER, MSGID_MAINTAIN, MSG_CFG_SAVE, NULL, 0);

}

static void confOnlineAndAlarm(AlarmEnv *pEnv) {
    char aMsgBuff[MAX_MSG_LEN];
    int msgLen;
    struct cmdunitl2 *pCmdList = NULL;
    struct cmdunitl2 *pCmdNode = NULL;
    int src;
    int seq;
    struct timespec delayTime = {0, 100000000};	// 100ms

#ifdef JCH_TEST
    char aBuff[1024];
    int len;
#endif
    pEnv->online = isOnline();
	if (kmsg_read(msgid, MSGID_ALMHANDLER, aMsgBuff, &msgLen) != NULL) {
        if (msg2cmdl2(aMsgBuff, msgLen, &pCmdList, &src, &seq) != -1) {
            pCmdNode = pCmdList;
            char cmd;
            Sensor *pSensor = NULL;
            char capType = 0;
            Capturer *pCapturer = NULL;
            while (pCmdNode != NULL) {

#ifdef JCH_TEST_XXX
                printBuff("CMD_NODE", pCmdNode->cmd, pCmdNode->len);
#endif

                switch (pCmdNode->type) {
                case MSG_ALARM_CONF:
                    pSensor = allocSensor(pCmdNode->cmd, &cmd);
                    processSensorCmd(&pEnv->pSensorList, pSensor, cmd);
                    saveAlarmConf(pEnv, global_config);
#ifdef JCH_TEST
                    memset(aBuff, 0, sizeof(aBuff));
                    len = sensorToBuff(aBuff, sizeof(aBuff), pSensor);
                    printBuff("SENSOR", aBuff, len);
                    printf("compare cmd and aBuff = %d\n", memcmp(pCmdNode->cmd, aBuff, len));
#endif

                    break;

                case MSG_ALARM_LISTEN:
                    pEnv->alarmMsgMask = *pCmdNode->cmd;	// NOTE:
                    saveAlarmConf(pEnv, global_config);
#ifdef JCH_TEST
                    printf("alarmMsgMask = %#02x\n", pEnv->alarmMsgMask);
#endif
                    break;

                    // TODO:
                case MSG_ALARM_RECORD:
                    pCapturer = allocCapturer(&capType, pCmdNode->cmd);
                    processCapturer(&pEnv->pCapList, pCapturer);
                    saveAlarmConf(pEnv, global_config);

#ifdef JCH_TEST
                    memset(aBuff, 0, sizeof(aBuff));
                    len = capturerToBuff(aBuff, sizeof(aBuff), pCapturer);
                    printBuff("CAPTURER", aBuff, len);
                    printf("compare cmd and aBuff = %d\n", memcmp(pCmdNode->cmd, aBuff, len));
#endif

                    break;

                case MSG_CFG_SAVE:
                    save_cfg(global_config);
                    break;

                case MSG_KCFG_SAVE:
                    save_key_cfg((struct BOARD_CFG_S *)(global_config + 1));
                    break;

                default:
                    LOGERROR("unknown message command for %d\n", pCmdNode->type);
                }
                pCmdNode = pCmdNode->next;
            }

            cmdfree(pCmdList);
            pCmdList = NULL;
        }
	}
	nanosleep(&delayTime, NULL);
}


// TODO:
void inspectVideoDiscard() {}
void inspectDetect() {}
void inspectVideoShield() {}
void inspectCodec() {}

static void cleanAllStatusLight()
{
    setI2cLedPinVal(g_gpioFD, I2CLED_3, I2CLED_PIN_OFF);
    setGPIOPinVal(g_gpioFD, GPIO_OUT_1 , false);
    setGPIOPinVal(g_gpioFD, GPIO_OUT_2 , false);
}

static void alarmStrategyThrd( struct almstatus *almStatus)
{
    if(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL))
        LOGERROR("set cancel type failed");
    LOGINFO("alarmOut1 = %d\talarmOut2 = %d\tonDelay=%d\toffDelay=%d\n",almStatus->alarmOut1,almStatus->alarmOut2,
            almStatus->ledOndelay,almStatus->ledOffdelay);
    cleanAllStatusLight();

    if( almStatus->alarmOut1 ) {
        setGPIOPinVal(g_gpioFD, GPIO_OUT_1 , true);
    }
    if( almStatus->alarmOut2 ) {
        setGPIOPinVal(g_gpioFD, GPIO_OUT_2 , true);
    }
    while(1) {
        if(!almStatus->alarming ) {
            //if()
        }

        if( 10 > almStatus->ledOndelay && almStatus->ledOndelay > 0 ) {
            setI2cLedPinVal(g_gpioFD, I2CLED_3, I2CLED_PIN_ON);
            sleep(almStatus->ledOndelay);
        } else {
            LOGERROR("delay time is out of range\n");
            break;
        }
        if( almStatus->ledOffdelay == 0 ) {
            continue;
        }
        if( 10 > almStatus->ledOffdelay && almStatus->ledOffdelay > 0 ) {
            setI2cLedPinVal(g_gpioFD, I2CLED_3, I2CLED_PIN_OFF);
            sleep(almStatus->ledOffdelay);
        } else {
            LOGERROR("delay time is out of range\n");
            break;
        }
    }
}

#define isExternAlarm1()        ( global_status->alarmType.extern_alarm1 == true )
#define isExternAlarm2()        ( global_status->alarmType.extern_alarm2 == true )
#define isExternAlarm3()        ( global_status->alarmType.extern_alarm3 == true )
#define isExternAlarm4()        ( global_status->alarmType.extern_alarm4 == true )


#define isHddErr()             ( global_status->alarmType.hdd_err == true )
#define isHddOver()            ( global_status->alarmType.hdd_over == true )
#define isVideoDiscard()       ( global_status->alarmType.video_discard == true )
#define isVideoShield()        ( global_status->alarmType.video_shield == true )
#define isCodecErr()           ( global_status->alarmType.codec_err == true )
#define isDynamicDetect()      ( global_status->alarmType.dynamic_detect == true )

bool setExternAlarming(char type)
{
    switch(type) {
        case 0:
            return (global_status->alarmType.extern_alarm1 = true);
        case 1:
            return (global_status->alarmType.extern_alarm2 = true);
        case 2:
            return (global_status->alarmType.extern_alarm3 = true);
        case 3:
            return (global_status->alarmType.extern_alarm4 = true);
        default:
            return false;
    }
}

bool cleanExternAlarming(char type)
{
    switch(type) {
        case 0:
            return (global_status->alarmType.extern_alarm1 = false);
        case 1:
            return (global_status->alarmType.extern_alarm2 = false);
        case 2:
            return (global_status->alarmType.extern_alarm3 = false);
        case 3:
            return (global_status->alarmType.extern_alarm4 = false);
        default:
            return false;
    }
}

bool isAlarming(AlarmType type)
{
    switch(type) {
        case EXTERN_ALARM1:
            return isExternAlarm1();
        case EXTERN_ALARM2:
            return isExternAlarm2();
        case EXTERN_ALARM3:
            return isExternAlarm3();
        case EXTERN_ALARM4:
            return isExternAlarm4();
        case HDD_ERR:
            return isHddErr();
        case HDD_OVER:
            return isHddOver();
        case VIDEO_SHIELD:
            return isVideoShield();
        case VIDEO_DISCARD:
            return isVideoDiscard();
        case CODEC_ERR:
            return isCodecErr();
        case DYNAMIC_DETECT:
            return isDynamicDetect();
        default:
            return false;
    }
}

static int detectRunningThrd(int *runningAlarm,int src,pthread_t *ttid)
{
     int alarm = *runningAlarm;
     int errno;
     if( alarm == src || alarm > src ) {
          return false;
     } else if( src > alarm && alarm > NORMAL_STATUS && *ttid > 0 ) {
          if( (errno = pthread_cancel(*ttid) ) ) {
               LOGERROR("Failed to cancel child thread,%s\n",strerror(errno));
          } else
               LOGINFO("thread has been canceled!ID = %ld\n",(unsigned long)*ttid);
     }
     if( *ttid > 0 && alarm == -1 ) {     /* Alarm should be canceled itself */
          if( (errno = pthread_cancel(*ttid) ) ) {
               LOGERROR("Failed to cancel child thread,%s\n",strerror(errno));
          } else
               LOGINFO("thread has been canceled!ID = %ld\n",(unsigned long)*ttid);
     }
     *runningAlarm = src;
     return true;
}

static void checkAlarmPriority(struct almstatus *strategyConf,int len,pthread_t *ttid)
{
     int     index;
     AlarmType   type;
     for(index = len - 1;index >= 0;index --) {
          type = strategyConf[index].alarmingType;
          if( type >= HDD_OVER && type <= DYNAMIC_DETECT ) {
               if( detectRunningThrd(&g_runningAlarm, type ,ttid) == true ) {
                    strategyConf[index].alarmOut1 = true;
                    strategyConf[index].alarmOut2 = true;
                    CreateThread(ttid, (void *)alarmStrategyThrd, &strategyConf[index] );
                    LOGINFO("thread Create!ID = %ld\n",(unsigned long)*ttid);
               }
          }
     }
}

static void strategyInit(struct almstatus *alarmStatus,int len,struct almtime *almtimer)
{
     cleanAllStatusLight();

     int i = 0;
     for( ;i < 4;i++) {
          alarmStatus[EXTERN_ALARM1 + i].ledOndelay = 9; /* second */
          alarmStatus[EXTERN_ALARM1 + i].ledOffdelay= 0; /* second */
          alarmStatus[EXTERN_ALARM1 + i].alarmMask = MM_EXTERN_MASK;
     }
     alarmStatus[EXTERN_ALARM1].alarmOutDelay = 5;

     alarmStatus[HDD_ERR].ledOndelay = 2;
     alarmStatus[HDD_ERR].ledOffdelay= 1;
     alarmStatus[HDD_ERR].alarmMask = MM_HDD_ERR_MASK;

     alarmStatus[HDD_OVER].ledOndelay = 2;
     alarmStatus[HDD_OVER].ledOffdelay= 2;
     alarmStatus[HDD_OVER].alarmMask= MM_HDD_OVER_MASK;

     alarmStatus[VIDEO_SHIELD].ledOndelay = 1;
     alarmStatus[VIDEO_SHIELD].ledOffdelay= 0;
     alarmStatus[VIDEO_SHIELD].alarmMask= MM_VIDEO_SHIELD_MASK;

     alarmStatus[VIDEO_DISCARD].ledOndelay = 1;
     alarmStatus[VIDEO_DISCARD].ledOffdelay= 0;
     alarmStatus[VIDEO_DISCARD].alarmMask= MM_VIDEO_DISCARD_MASK;

     alarmStatus[CODEC_ERR].ledOndelay = 1;
     alarmStatus[CODEC_ERR].ledOffdelay= 0;
     alarmStatus[CODEC_ERR].alarmMask= MM_CODEC_ERR_MASK;

     alarmStatus[DYNAMIC_DETECT].ledOndelay = 1;
     alarmStatus[DYNAMIC_DETECT].ledOffdelay= 0;
     alarmStatus[DYNAMIC_DETECT].alarmMask= MM_DETECT_MASK;

     almtimer[0].endTime = almtimer[1].endTime = almtimer[2].endTime = almtimer[3].endTime = time(NULL);
}

static void alarmStrategy(struct  almstatus *alarmStatus,int len,char alarmMsgMask,Sensor *pSensorList, Capturer *pCapList,struct almtime *almTimer)
{
    int         errno,index,alarmSensor = 0;
    time_t      almTime;
    AlarmType   type = 0;
    Sensor      *pSensor = pSensorList;
    if( !isExternAlarm1()
        && !isExternAlarm2()
        && !isExternAlarm3()
        && !isExternAlarm4()
        && !isHddErr()
        && !isHddOver()
        && !isCodecErr()
        && !isVideoShield()
        && !isVideoDiscard()
        && !isDynamicDetect() ) {

        if( tid > 0 ) {
            //cleanAllStatusLight();
            if( alarmStatus[EXTERN_ALARM1].alarmingType == EXTERN_ALARM1
                ||alarmStatus[EXTERN_ALARM2].alarmingType == EXTERN_ALARM2
                ||alarmStatus[EXTERN_ALARM3].alarmingType == EXTERN_ALARM3
                ||alarmStatus[EXTERN_ALARM4].alarmingType == EXTERN_ALARM4) {
                setI2cLedPinVal(g_gpioFD, I2CLED_3, I2CLED_PIN_OFF);
            }
            else {
                cleanAllStatusLight();
            }
            for(type = 0;type < len;type++)  /* clear all alarm flag  */
                alarmStatus[type].alarmingType = -1;
            LOGINFO("thread has been canceled!ID = %ld,g_runningAlarm = %d\n",(unsigned long)tid,g_runningAlarm);
        }

        while( pSensor != NULL ) {
            index = pSensor->conf.addr - 1;
            if( almTimer[index].outDelay >= 0 && almTimer[index].alarming ) {
                dbg(" off : diff %f,index = %d,alarming = %d",
                    difftime(time(NULL),( almTimer[index].endTime + almTimer[index].sensitivity ) ),index,almTimer[index].alarming );
                if ( difftime(time(NULL),( almTimer[index].endTime + almTimer[index].sensitivity ) ) >= almTimer[index].outDelay ) {
                    almTimer[index].alarming = false;
                    Sensor *sensor = pSensorList;
                    for(;sensor != NULL;sensor = sensor->pNext) {
                        if( almTimer[sensor->conf.addr - 1].alarming && sensor->conf.addr != pSensor->conf.addr) {
                            LOGINFO("another extern alarm has not been ended yet.\n");
                            goto KeepGPIO;
                        }
                    }
                    setGPIOPinVal(g_gpioFD, GPIO_OUT_1 , false);
                    setGPIOPinVal(g_gpioFD, GPIO_OUT_2 , false);
                    LOGINFO("out off\n");
                    break;
                }
            }
            pSensor = pSensor->pNext;
        }
    KeepGPIO:

        if( tid > 0 && ( errno = pthread_cancel(tid) ) ) {
            LOGERROR("Failed to cancel child thread,%s\n",strerror(errno));
        }
        if( tid )
            tid = 0;

        if( g_runningAlarm != NORMAL_STATUS)
            g_runningAlarm = NORMAL_STATUS;

        for( type = 0;type < len;type++ ) {
            if( alarmStatus[type].alarming )
                goto pNext;
        }
        return;
    }

    if( isAlarming(EXTERN_ALARM1) || isAlarming(EXTERN_ALARM2) || isAlarming(EXTERN_ALARM3) ||isAlarming(EXTERN_ALARM4)) {
        pSensor = pSensorList;
        while( pSensor != NULL ) {
            if( pSensor->alarming && pSensor ->conf.enable) {
                if(alarmSensor < pSensor ->conf.addr) {
                    alarmSensor = pSensor ->conf.addr;
                }
            }
            pSensor = pSensor->pNext;
        }
        pSensor = pSensorList;
        while( pSensor != NULL ) {
            if(alarmSensor == pSensor ->conf.addr) {
                switch(pSensor->conf.slAddr) {
                case 1:
                case 2:
                case 3:
                case 4:
                    if( pSensor->conf.slAddr == 1 ) {
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut1 = true;
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut2 = false;
                    }
                    else if( pSensor->conf.slAddr == 2 ) {
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut1 = false;
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut2 = true;
                    }
                    else if( pSensor->conf.slAddr == 3 ) {
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut1 = true;
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut2 = true;
                    }
                    else if( pSensor->conf.slAddr == 4 ) {
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut1 = false;
                        alarmStatus[EXTERN_ALARM1 + pSensor->conf.addr - 1].alarmOut2 = false;
                    }
                    break;
                }
            }
            pSensor = pSensor->pNext;
        }
    }


pNext:
    time(&almTime);
    struct tm *pTime = gmtime(&almTime);
    type = 0;
    while(type < len) {
        if( ( ( isAlarming(type) && !alarmStatus[type].alarming )
              || ( !isAlarming(type) && alarmStatus[type].alarming ) )
            && ( type != EXTERN_ALARM1 && type != EXTERN_ALARM2 && type != EXTERN_ALARM3 && type != EXTERN_ALARM4 )
            && ( ( alarmMsgMask & alarmStatus[type].alarmMask ) == alarmStatus[type].alarmMask ) ) {
            dbg("send ipc msg,alarming = %d,mask = %d",alarmStatus[type].alarming,
                ( ( alarmMsgMask & alarmStatus[type].alarmMask ) == alarmStatus[type].alarmMask ));
            sendAlmMsg(msgid, 1, alarmStatus[type].alarmMask, 0, isAlarming(type)?ALARM_TYPE_ACTIVE:ALARM_TYPE_DEACTIVE, 1, pTime);
        }

        if( isAlarming(type) ) {
            if( !alarmStatus[type].alarming ) {
                alarmStatus[type].alarming = true;
            }
            if( alarmStatus[type].alarmingType != type ) {
                alarmStatus[type].alarmingType = type;
            }

        } else {
            if( alarmStatus[type].alarmingType != NORMAL_STATUS ) {
                alarmStatus[type].alarmingType = NORMAL_STATUS;
            }
            if( alarmStatus[type].alarming ) {
                alarmStatus[type].alarming = false;
            }
            if(g_runningAlarm == type ) {
                g_runningAlarm = -1;
            }
        }
        type++;
    }
    checkAlarmPriority(alarmStatus, len, &tid);
}
/*
  void alarm_action_send(Sensor *pSensor)
  {
  unsigned int act = getInt(pSensor->conf.aActions);
  if (act & AA_RECORD_MASK) {
  startAlmRec(msgid, pCapList, pSensor->conf.recId,(char)getShort(pSensor->conf.aRecordDelays) ,recSecond);
  LOGINFO("will alarm record\n");
  }

  if (act & AA_SNAP_SHOT_MASK) {
  startSnapShot(msgid, pSensor->conf.snapChn, pSensor->conf.snapInterSec, pTime);
  LOGINFO("will alarm snapshot\n");
  }

  //if( act & AA_PTZ_MASK ) {
  if(1) {
  pSensor->conf.panTiltType = 3;
  pSensor->conf.panTiltAddr = 1;
  }
  }
*/
static void detectSensor(Sensor *pSensorList,struct almtime *almTm,char alarmMsgMask)
{
    Sensor  *pSensor = pSensorList;
    int     index;
    time_t  almTime;
    time(&almTime);
    struct tm *pTime = gmtime(&almTime);
   	for ( ;pSensor != NULL;pSensor = pSensor->pNext) {
        index = pSensor->conf.addr - 1;
        unsigned int act = getInt(pSensor->conf.aActions);
        if( pSensor->alarming ) {
            if( isAlarming(index + EXTERN_ALARM1) )
                continue;
            kshm_lock(shmid_status);
            setExternAlarming(index);
            kshm_unlock(shmid_status);
            almTm[index].alarmCancel = false;
            if( alarmMsgMask & MM_EXTERN_MASK ) {
                sendAlmMsg(msgid, pSensor->conf.addr, MM_EXTERN_MASK, act & AA_SNAP_SHOT_MASK, ALARM_TYPE_ACTIVE, pSensor->conf.snapChn, pTime);
            }
            continue;
        } else {
            //dbg(" Unalarm: %d alarm,alarming = %d",(index + EXTERN_ALARM1),almTm[index].alarming);
            if( isAlarming(index + EXTERN_ALARM1) && almTm[index].alarming ) {
                dbg("time to decide alarm false : %f,index = %d,alarmCancel = %d",difftime(time(NULL),almTm[index].endTime) ,index,almTm[index].alarmCancel);
                if( !almTm[index].alarmCancel && difftime(time(NULL),almTm[index].endTime) >= almTm[index].sensitivity ) {
                    kshm_lock(shmid_status);
                    cleanExternAlarming(index);
                    kshm_unlock(shmid_status);
                    almTm[index].alarmCancel = true;
                    if( alarmMsgMask & MM_EXTERN_MASK/* && almTm[index].sensitivity != 0*/) {
                        sendAlmMsg(msgid, pSensor->conf.addr, MM_EXTERN_MASK, act & AA_SNAP_SHOT_MASK, ALARM_TYPE_DEACTIVE, pSensor->conf.snapChn, pTime);
                    }

                    if( getInt(pSensor->conf.aActions) & AA_PTZ_MASK ) {
                        startPtzCmd(msgid,pSensor->conf.addr - 1 ,0, pSensor->conf.panTiltAddr ,0);
                    }
                } else {
                    if(!almTm[index].alarmCancel )
                        almTm[index].alarmCancel = false;
                }
            }
        }
    }
}


static void quitALMProc(int sigNo) {
     if (sigNo == SIGTERM || sigNo == SIGINT) {
          LOGINFO("get SIGTERM or SIGINT,%d\n",sigNo);
          env.quit = true;
     }
}

int main(void)
{
     int     len = TOTAL_ALARM_TYPE;
     struct  timespec    delayTime = {0, 100000000};	// 100ms
     struct  almstatus   alarmStatus[TOTAL_ALARM_TYPE] = {};
     //struct  almtime     almTime[SENSOR_NUM] = {};
     if (initIPC() < 0) {
          printf("initIPC() < 0\n");
          return -1;
     }
     signal(SIGTERM, quitALMProc);
     signal(SIGINT, quitALMProc);

     loadDefaultConf(&env, ALARM_CONF_FN);
     env.gpioFD = open(GPIO_DEV_FN, O_RDWR);
     if (env.gpioFD < 0) {
          printf("env.gpioFD < 0\n");
          return -1;
     }
     g_gpioFD = env.gpioFD;
     strategyInit(alarmStatus, TOTAL_ALARM_TYPE,env.almTime);
     while(!env.quit){
          confOnlineAndAlarm(&env);

          inspectVideoDiscard();
          inspectDetect();
          inspectVideoShield();
          inspectCodec();
          inspectSensor(msgid,
                        env.alarmMsgMask,
                        env.gpioFD,
                        env.pSensorList,
                        env.pCapList,
                        global_config->hddConf.rsSchedule[24]*60,env.almTime);
          detectSensor(env.pSensorList,env.almTime,env.alarmMsgMask);
          alarmStrategy(alarmStatus,len,env.alarmMsgMask,env.pSensorList,env.pCapList,env.almTime);
          alarmFeedDog();
          nanosleep(&delayTime, NULL);
     }
     LOGINFO("process break......\n");

     close(env.gpioFD);
     freeCapturerList(env.pCapList);
     freeSensorList(env.pSensorList);

     _exit(0); /* Any open file descriptors belonging to the process should be closed; */
}

